const axios = require('axios');
const logger = require('./Logger.js');
const config = require('./config.js');
const DEB = config.debLog;

class TokenManager {
    constructor() {
        this.tokensMap = new Map();
        this.locksMap = new Map();
        this.DEFAULT_EXPIRE_TIME = 7200;
    }

    async getAccessToken(appid, secret, forceRefresh = false) {
        if (!appid) {
            throw new Error('appid不能为空');
        }

        const tokenInfo = this.tokensMap.get(appid);
        const now = Date.now();
        if (tokenInfo && tokenInfo.access_token && tokenInfo.expire_time > now && !forceRefresh) {
            return tokenInfo.access_token;
        }

        const tokenLock = this._getLock(appid);
        if (tokenLock.locked) {
            const waitStart = now;
            while (tokenLock.locked && Date.now() - waitStart < 5000) {
                await new Promise(resolve => setTimeout(resolve, 100));
            }
            if (tokenLock.locked) {
                throw new Error(`获取appid: ${appid}的access token超时`);
            }
            const updatedTokenInfo = this.tokensMap.get(appid);
            if (updatedTokenInfo && updatedTokenInfo.access_token && updatedTokenInfo.expire_time > Date.now() && !forceRefresh) {
                return updatedTokenInfo.access_token;
            }
        }
        this._acquireLock(appid);

        try {
            const checkTokenInfo = this.tokensMap.get(appid);
            if (checkTokenInfo && checkTokenInfo.access_token && checkTokenInfo.expire_time > Date.now() && !forceRefresh) {
                return checkTokenInfo.access_token;
            }
            // 请求新token
            const tokenData = await this._queryAccessToken(appid, secret);
            this.tokensMap.set(appid, {
                access_token: tokenData.access_token,
                expire_time: Date.now() + (tokenData.expires_in || this.DEFAULT_EXPIRE_TIME) * 1000 - 60000,
                create_time: Date.now()
            });
            DEB && console.info(`成功获取并存储appid: ${appid}的access token`);
            return tokenData.access_token;
        } finally {
            this._releaseLock(appid);
        }
    }

    async _queryAccessToken(appid, secret) {
        try {
            const response = await axios.post(
                'https://minigame.zijieapi.com/mgplatform/api/apps/v2/token',
                {
                    appid: appid,
                    grant_type: 'client_credential',
                    secret: secret
                },
                {
                    headers: {
                        'Content-Type': 'application/json'
                    }
                }
            );
            DEB && console.info(`获取appid: ${appid}的access token结果：${JSON.stringify(response.data)}`);
            if (response.data.err_no === 0 && response.data.data?.access_token) {
                return response.data.data;
            } else {
                logger.logMessage(`获取appid: ${appid}的access token失败，${response.data.err_tips || '数据异常'}`);
                throw new Error(`获取appid: ${appid}的access token失败，${response.data.err_tips || '数据异常'}`);
            }
        } catch (error) {
            logger.logMessage(`获取appid: ${appid}的access token失败，${error.message}`);
            throw new Error(`获取appid: ${appid}的access token失败，${error.message}`);
        }
    }

    // 获取指定appid的锁
    _getLock(appid) {
        if (!this.locksMap.has(appid)) {
            this.locksMap.set(appid, { locked: false, timeout: null });
        }
        return this.locksMap.get(appid);
    }

    // 为指定appid加锁
    _acquireLock(appid) {
        const lock = this._getLock(appid);
        lock.locked = true;
        lock.timeout = setTimeout(() => {
            lock.locked = false;
            DEB && console.warn(`appid: ${appid}的token锁超时自动释放`);
        }, 5000);
    }

    // 释放指定appid的锁
    _releaseLock(appid) {
        const lock = this.locksMap.get(appid);
        if (lock) {
            clearTimeout(lock.timeout);
            lock.locked = false;
        }
    }

    // 清除指定appid的token（可选方法，方便手动刷新）
    clearToken(appid) {
        if (appid) {
            this.tokensMap.delete(appid);
            DEB && console.info(`已清除appid: ${appid}的access token`);
        } else {
            // 如果没有指定appid，则清除所有token
            this.tokensMap.clear();
            DEB && console.info('已清除所有access token');
        }
    }

    // 获取当前管理的所有token信息（可选方法，用于调试）
    getTokensInfo() {
        const info = {};
        this.tokensMap.forEach((value, key) => {
            info[key] = {
                access_token: value.access_token ? '已存在' : '不存在',
                expire_time: new Date(value.expire_time).toISOString(),
                is_expired: value.expire_time < Date.now()
            };
        });
        return info;
    }
}

module.exports = TokenManager;